/**
 * 
 * @author waitingsnow
 * $Id: ObjectPoolUtil.as 2 2012-05-17 10:10:03Z cgslendy@gmail.com $
 */
package com.waitingsnow.core.util.display
{
import flash.utils.Dictionary;
import flash.utils.getDefinitionByName;
import flash.utils.getQualifiedClassName;

/**
 * Manages objects by retaining disposed objects and returning them when a new object
 * is requested, to avoid unecessary object creation and disposal and so avoid
 * unnecessary object creation and garbage collection.
 */
public class ObjectPoolUtil
{
	private static var pools:Dictionary = new Dictionary();
	
	private static function getPool(type:Class):Array
	{
		return (type in pools) ? pools[type] : (pools[type] = []);
	}
	
	/**
	 * Get an object of the specified type. If such an object exists in the pool then
	 * it will be returned. If such an object doesn't exist, a new one will be created.
	 *
	 * @param type The type of object required.
	 * @param parameters If there are no instances of the object in the pool, a new one
	 * will be created and these parameters will be passed to the object constrictor.
	 * Because you can't know if a new object will be created, you can't rely on these
	 * parameters being used. They are here to enable pooling of objects that require
	 * parameters in their constructor.
	 */
	public static function getObject(type:Class, ...parameters):*
	{
		var pool:Array = getPool(type);
		if(pool.length > 0)
		{
			return pool.pop();
		}
		else
		{
			return new2(type, parameters);
		}
	}
	
	/**
	 * Return an object to the pool for retention and later reuse. Note that the object
	 * still exists, so you need to clean up any event listeners etc. on the object so
	 * that the events stop occuring.
	 *
	 * @param object The object to return to the object pool.
	 * @param type The type of the object. If you don't indicate the object type then the
	 * object is inspected to find its type. This is a little slower than specifying the
	 * type yourself.
	 */
	public static function collectObject(object:*, type:Class = null):void
	{
		if(!type)
		{
			var typeName:String = getQualifiedClassName(object);
			type = getDefinitionByName(typeName) as Class;
		}
		var pool:Array = getPool(type);
		pool.push(object);
	}
	
	public static function disposeObject(type:Class):void
	{
		if (pools[type])
		{
			delete pools[type];
		}
	}
	
	public static function new2(type:Class, args:*):*
	{
		switch (args.length)
		{
			case 0:
				return new type();
			case 1:
				return new type(args[0]);
			case 2:
				return new type(args[0], args[1]);
			case 3:
				return new type(args[0], args[1], args[2]);
			case 4:
				return new type(args[0], args[1], args[2], args[3]);
			default:
				return null;
		}
	}
}
}